﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using FileParser;
using System.Threading;

namespace _2D_GUI
{
    public delegate void EMDel(string message);
    public delegate void eventDel(object sender, EventArgs e);
    public delegate void scrollDel();

    /// <summary>
    /// The graphical user interface.
    /// Loads and sets up menus, controls, and event handlers.
    /// Paints to the screen via an animation box.
    /// </summary>
    public partial class GUI : Form
    {
        // ???
        private const int baseH = 100, baseW = 100;
        // Used to determine if there is an existed SVN connection
        private bool isSVNHooked = false;
        // The point in the form at which the mouse was clicked 
        private Point mouseClickPos;
        // Holds all animation data for a single project
        private C_DataStructure[][] projectDataStructure = null; // ONE BASED!!!!  
        // ???
        private int projectValidLength = 1; //A length variable for filled  spots (ignore first spot)
        // Translated from projectDataStructure. Animation will be drawn directly from this array
        private C_Shape[][] projectRevisionArray = null;
        // Handles SVN connection
        private C_SVNInterface svnHook = null;
        // The current value of the track bar
        private int trackVal = 0;
        // Used to determine if the animation is currently playing
        private bool isPlaying = false;
        // ???
        private Thread playThread;
        // ???
        private Thread updateThread;

        /// <summary>
        /// Brief Constructor.
        /// Sets up the graphical user interface.
        /// </summary>
        public GUI()
        {
            // Set screen size (full)
            WindowState = FormWindowState.Maximized;
            InitializeComponent();
        }

        /// <summary>
        /// Is called when a click event happens inside the animation box.
        /// Determines if the user clicked inside a shape.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickAnimationBox(object sender, MouseEventArgs e)
        {
            // The point where the mouse was clicked relative to the screen
            Point screenPos = Control.MousePosition;
            // The point where the mouse was clicked relative to the form.
            mouseClickPos.X = this.PointToClient(screenPos).X;
            mouseClickPos.Y = this.PointToClient(screenPos).Y - 25;
            Point mouseClickPoint = new Point(mouseClickPos.X, mouseClickPos.Y);
            string shapeInfo = null;

            // Determine if the click occured inside the bounds of one or more shapes
            try
            {
                // Get the current revision and check all the its shapes to see if they were clicked
                if (projectRevisionArray != null && trackBar.Value < projectRevisionArray.Length)
                    shapeInfo = FindClickedShape(mouseClickPoint, projectRevisionArray[trackBar.Value]);
                // A shape was clicked on
                if (shapeInfo != null)
                {
                    // Display a tooltip pop-up containing information on the clicked shape
                    System.Windows.Forms.ToolTip shapePopUp = new System.Windows.Forms.ToolTip();
                    shapePopUp.SetToolTip(this.AnimationBox, shapeInfo);
                    shapePopUp.Show(shapeInfo, this, mouseClickPos.X, mouseClickPos.Y + 25, 1);
                    shapePopUp.Hide(this);
                }
            }
            catch
            {
                System.Diagnostics.Debug.WriteLine("An error occureed in the Click animation");
            }
        }

        /// <summary>
        /// Is called when "Connect to SVN" is clicked on from the File Menu.
        /// Prompts the user to enter a SVN address and downloads the repository.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickFileConnect(object sender, EventArgs e)
        {
            // Displays a dialog asking the user for the URL of an SVN repository
            SVN_Popup dialogue = new SVN_Popup();
            DialogResult result = dialogue.ShowDialog(this);

            // Did the user cancel the operation?
            if (result != DialogResult.OK)
                return;

            // URL of the SVN repository
            string address = dialogue.GetStringInput();

            System.Diagnostics.Debug.WriteLine("SVN called, address is: " + address);

            // Alright, at this point, the program should split off a new thread
            // to interact with the SVN (through interface).

            // The main gui should be mostly paused, with some update via
            // status bar or whatnot. It's actually possible to create
            // a system that would keep on operating normally while the
            // downloading was going on in the background with little difficulty.
            // I will assume that this is what we are going for?

            // Another note here, there should be protection here to prevent
            // the user from opening multiple projects. Thinking a global
            // variable/boolean.

            // Create a new SVN connection
            svnHook = new C_SVNInterface(address, "SVN Connection");

            (updateThread = new Thread(GetAllRevisions)).Start();
        }

        /// <summary>
        /// Is called when "Open Animation" is clicked on from the File Menu.
        /// Opens a dialog box so the user can open a previously saved animation
        /// in the .GENMA format.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ClickFileOpen(object sender, EventArgs e)
        {
            // Display and Open File Dialog box
            OpenFileDialog OFD = new OpenFileDialog();
            OFD.Title = "Open Animation File";
            OFD.CheckFileExists = true;
            OFD.CheckPathExists = true;
            OFD.Filter = "Animation Files (*.GENMA)|*.GENMA|All files (*.*)|*.*";
            OFD.AddExtension = true;
            OFD.DefaultExt = ".GENMA";
            OFD.Multiselect = false;

            // Did the user cancel the operation?
            if (OFD.ShowDialog() == DialogResult.OK)
            {
                // File to open
                projectLocationTextBox.Text = OFD.FileName;

                // Attempt Load the project data structure from file
                C_DataStructure[][] loadAttempt = C_Storage.LoadFromFile(OFD.FileName);

                // Display an error if the file could not be loaded properly
                if (loadAttempt == null)
                    this.BeginInvoke(new EMDel(ShowErrorMessage), new string[] { "The file: " + OFD.FileName + " is not a valid animation file, or was corrupt." });
                // Load the project data structure
                else
                {
                    // Copy the data structure from our load attempt
                    projectDataStructure = loadAttempt;
                    projectValidLength = projectDataStructure.Length;

                    // Translates the data structure into the animation data structure
                    TranslateRevision();
                    // Redraw the animation
                    AnimationBox.Invalidate();
                }
            }
        }

        /// <summary>
        /// Is called when "Quit" is clicked on from the File Menu.
        /// Exits the program.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ClickFileQuit(object sender, EventArgs e) 
        { 
            // Exit!
            Application.Exit(); 
        }

        /// <summary>
        /// Is called when "Save Animation" is clicked on from the File Menu.
        /// Displays a File Save dialog box so the user can save the current
        /// animation in .GENMA format.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickFileSave(object sender, EventArgs e)
        {
            // Display error if there is no project to save
            if (projectDataStructure == null)
            {
                this.BeginInvoke(new EMDel(ShowErrorMessage), new string[] { "No project open. Either connect to a server or load an animation from the file menu." });
                return;
            }

            // Create a new save file dialog box
            SaveFileDialog SFD = new SaveFileDialog();
            SFD.Title = "Save Animation File";
            SFD.AddExtension = true;
            SFD.CheckFileExists = false;
            SFD.CheckPathExists = true;
            SFD.DefaultExt = ".GENMA";
            SFD.Filter = "Animation Files (*.GENMA)|*.GENMA|All files (*.*)|*.*";
            SFD.CreatePrompt = false;

            // Save the project data to disk.
            if (SFD.ShowDialog() == DialogResult.OK)
            {
                C_Storage.SaveToFile(projectDataStructure, SFD.FileName, projectValidLength);
            }
        }

        /// <summary>
        /// Is called when the user clicks "FAQ" from the Help Menu.
        /// Directs the users internet browser to our FAQ webpage.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickHelpFAQ(object sender, EventArgs e)
        {
            // Direct the clients internet browser to the URL
            System.Diagnostics.Process.Start("http://sites.google.com/site/cop4331group4/detaileddesigntemplate");
        }

        /// <summary>
        /// Is called when the user clicks on "User Manual" from the Help Menu.
        /// Directs the user internet browser to our Help Manual webpage.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickHelpUserManual(object sender, EventArgs e)
        {
            // Direct the clients internet browser to the URL
            System.Diagnostics.Process.Start("http://sites.google.com/site/cop4331group4/detaileddesigntemplate");
        }

        /// <summary>
        /// Is called when the user clicks on "Play" from the Navigation Menu
        /// or when the user clicks the Play button.
        /// Displays each version frame consecutively.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickNavPlay(object sender, EventArgs e)
        {
            // Check if the animation is currently playing
            if (!isPlaying)
                // Creates a new thread to handle playing
                (playThread = new Thread(Play)).Start();
            
            // Plays if not currently playing, pauses otherwise
            isPlaying = !isPlaying;
        }

        /// <summary>
        /// Is called when "Blue" is selected under "Change Background"
        /// in the View Menu.
        /// Changes the background color of all controls to blue.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickViewBlue(object sender, EventArgs e)
        {
            // Set all the background colors to blue
            this.trackBar.BackColor = System.Drawing.Color.Blue;
            this.AnimationBox.BackgroundImage = null;
            this.BackColor = System.Drawing.Color.Blue;
        }

        /// <summary>
        /// Is called when "Default" is selected under "Change Background"
        /// in the View Menu.
        /// Changes the background color of all controls to gray.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickViewDefault(object sender, EventArgs e)
        {
            // Set all the background colors to gray.
            this.trackBar.BackColor = System.Drawing.Color.LightGray;
            this.AnimationBox.BackgroundImage = null;
            this.BackColor = System.Drawing.Color.LightGray;
        }

        /// <summary>
        /// Is called when "Image" is selected under "Change Background"
        /// in the View Menu.
        /// Changes the background of the animation box to an image specified
        /// by the user.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClickViewImage(object sender, EventArgs e)
        {
            // Display an open dialog box so the user can select an image
            OpenFileDialog OFD = new OpenFileDialog();
            OFD.Title = "Open Image File";
            OFD.CheckFileExists = true;
            OFD.CheckPathExists = true;
            // Check if the user canceled the operation
            if (OFD.ShowDialog() == DialogResult.OK)
            {
                // Set the animation box background to the image
                this.AnimationBox.BackgroundImage = Image.FromFile(OFD.FileName);
            }
        }

        /// <summary>
        /// Is called when the form is closed.
        /// Aborts all currently running threads.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CloseGUI(object sender, FormClosedEventArgs e)
        {
            CloseGUI();
        }

        /// <summary>
        /// Is called when the form is closed.
        /// Aborts all currently running threads.
        /// </summary>
        private void CloseGUI()
        {
            // Close thread handling playing
            if (isPlaying)
                playThread.Abort();

            // Close SVN connection
            if (svnHook != null)
                svnHook.Close();

            // Close thread handling SVN connection
            if (isSVNHooked)
                updateThread.Abort();
        }

        /// <summary>
        /// Converts the data structure representing all versions of
        /// a Subversion project to an array of C_Shapes which can be
        /// used to directly draw a visual representation.
        /// </summary>
        /// <param name="data"></param>
        /// <returns>Array of shapes</returns>
        public C_Shape[] ConvertDataToTree(C_DataStructure[] data)
        {
            System.Diagnostics.Debug.WriteLine("Convert to Tree Called - data input size " + data.Length);

            // Empty project
            if (data.Length == 0)
                return new C_Shape[0];

            bool[] root = new bool[data.Length];

            for (int i = 0; i < root.Length; i++)
                root[i] = true;

            C_Shape[] shapeList = new C_Shape[data.Length];

            for (int i = 0; i < shapeList.Length; i++)
                shapeList[i] = new C_Box(data[i], new Size(data[i].GetNumFunctions(), data[i].GetNumVariables()), new Point(), Color.Blue, new C_Shape[0]);

            System.Diagnostics.Debug.WriteLine("    converting... shapelist size: " + shapeList.Length);

            for (int i = 0; i < data.Length; i++)
            {
                if (data[i].GetInheritance() == "none")
                    continue;
                for (int j = i + 1; j < data.Length; j++)
                {
                    if (data[i].GetRefId() == data[j].GetInheritance())
                    {
                        root[j] = false;
                        shapeList[i].AddInheriter(shapeList[j]);
                    }
                    else if (data[j].GetName() == data[i].GetInheritance())
                    {
                        root[i] = false;
                        shapeList[j].AddInheriter(shapeList[i]);
                    }
                }
            }

            List<C_Shape> preret = new List<C_Shape>();

            for (int i = 0; i < data.Length; i++)
                if (root[i])
                    preret.Add(shapeList[i]);

            System.Diagnostics.Debug.WriteLine("TreeConvert size: " + preret.Count);

            return preret.ToArray();
        }

        /// <summary>
        /// Determines if a shape was clicked on and if so, which shape.
        /// </summary>
        /// <param name="mouseClickPos"></param>
        /// <param name="shapeArray"></param>
        /// <returns>Information about the shape.</returns>
        private string FindClickedShape(Point mouseClickPos, C_Shape[] shapeArray)
        {
            try
            {
                // Look at all the shapes
                for (int i = 0; i < shapeArray.Length; i++)
                {
                    // Get the lower and upper bounds for each shape
                    int shapeLowerX = shapeArray[i].GetLocation().X;
                    int shapeLowerY = shapeArray[i].GetLocation().Y;
                    int shapeUpperX = shapeArray[i].GetSize().Width + shapeLowerX;
                    int shapeUpperY = shapeArray[i].GetSize().Height + shapeLowerY;

                    // Determine if the mouse click happened within the bounds of the current shape
                    if (mouseClickPos.X > shapeLowerX && mouseClickPos.Y > shapeLowerY
                        && mouseClickPos.X < shapeUpperX && mouseClickPos.Y < shapeUpperY)
                    {
                        // Is there another shape inheriting from the current shape?
                        if (shapeArray[i].GetInheritance() != null)
                        {
                            // Get information on the inheriting shape
                            string childInfo = FindClickedShape(mouseClickPos, shapeArray[i].GetInheritance());
                            
                            // Remove the repeated namespace information from the child shape information
                            int j = 0;
                            if(childInfo != null)
                                while (childInfo[j] != ':')
                                {
                                    j++;
                                }
                            if (childInfo != null)
                                return shapeArray[i].GetName() + "::" + childInfo[j+2];
                        }
                        // Return information about of shape
                        return shapeArray[i].GetName() + " Contains " + shapeArray[i].GetNumVariables() + " variable and " + shapeArray[i].GetNumFunctions() + " methods.";
                    }
                }
                // No shape was found
                return null;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// Get all versions from a Subversion repository.
        /// </summary>
        public void GetAllRevisions()
        {
            // Check to see if a previous connection exists
            if (isSVNHooked == true)
            {
                ShowErrorMessage("There is already a connection in progress!");
                return;
            }
            
            //Zero means there is no such server. Should have
            // some sort of "You screwed up" dialog box.
            if (svnHook.GetRevs() == 0)
            {
                this.BeginInvoke(new EMDel(ShowErrorMessage), new string[] { "The server name: " + svnHook.GetLoc() + " was invalid." });
                return;
            }

            // SVN connection in progress
            isSVNHooked = true;

            // Get number of revisions in the project
            int revisions = svnHook.GetRevs();
            System.Diagnostics.Debug.WriteLine("revs: " + revisions);
            
            // Create a new data structure to hold the project
            projectDataStructure = new C_DataStructure[revisions+1][];

            // Place each revision into the data structure
            for (int i = 1; i < projectDataStructure.Length; i++)
            {
                System.Diagnostics.Debug.WriteLine("Made it to revision" + i);
                // Insert current revision into data structure
                projectDataStructure[i] = svnHook.ProcessRevision(i);
                projectValidLength = i+1;              
                // Redraw animation   
                AnimationBox.Invalidate();
            }

            //Supah Debug
            //C_Storage.SaveToFile(projectDataStructure, "TestStore.txt", projectValidLength);

            // Convert data structure to a structure that can be used to directly draw the animation
            TranslateRevision();

            // SVN connection no longer in progress
            isSVNHooked = false;

            // Redraw animation
            AnimationBox.Invalidate();
        }

        /*
         * 
         * ARCHIVED FOR EXAMPLE FOR INTERACTING WITH THE SVN HOOK
        public void GetAllRevTest()
        {
            //Zero means there is no such server. Should have
            // some sort of "You screwed up" dialog box.
            if (svnHook.GetRevs() == 0)
            {
                this.BeginInvoke(new EMDel(ErrorMessage), new string[] { "The server name: " + svnHook.GetLoc() + " was invalid." });
                return;
            }

            //NOTA! THIS WILL EVENTUALLY BE CHANGED TO svnHook.getRevs()
            for (int i = 1; i < 13; i++)
                foreach (C_DataStructure C in svnHook.ProcessRevision(i))
                    System.Diagnostics.Debug.WriteLine(C);
        }
         * */
        /// <summary>
        /// Needed to load the GUI.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LoadGUI(object sender, EventArgs e)
        {
            Console.WriteLine("GUI Successfully loaded");
        }

        /// <summary>
        /// Is called when the animation needs to be refreshed.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            PaintAnimationBox(this, e);
            base.OnPaint(e);
        }

        /// <summary>
        /// Paints buttons, shapes, and controls to the animation box.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PaintAnimationBox(object sender, PaintEventArgs e)
        {
            // Display the control buttons
            this.PreviousButton.Bounds = new Rectangle(0, this.Height - 115, 30, 40);
            this.PlayButton.Bounds = new Rectangle(this.PreviousButton.Width, this.Height - 115, 40, 40);
            this.NextButton.Bounds = new Rectangle(this.PreviousButton.Width + this.PlayButton.Width, this.Height - 115, 30, 40);
            
            // Determine how much space the buttons take up
            int buttonOffset = PlayButton.Width + PreviousButton.Width + NextButton.Width;

            // Display the trackbar next to the buttons
            trackBar.SetBounds(buttonOffset, this.Height - 105, this.Width - 10 - buttonOffset, 10);
            trackBar.BringToFront();

            // Displays where the current project is loaded from
            projectLocationTextBox.SetBounds(0, this.Height - 78, this.Width, 0);
            projectLocationTextBox.BringToFront();
            
            // Displays the progress of the current SVN repository download
            ProgressBar.Value = (projectValidLength-1) 
                * 100/(projectDataStructure == null? 100 : projectDataStructure.Length-1);
            if (projectDataStructure == null || projectValidLength == projectDataStructure.Length)
                ProgressBar.Value = 0;
            
            // Display animation box
            AnimationBox.SetBounds(0, 25, this.Width, this.Height - 82); // Numbers chosen to fit with tool and status bars

            // Get Equipment
            Graphics g = e.Graphics;
            Brush red = new SolidBrush(Color.Red);
            Brush blue = new SolidBrush(Color.Blue);
            Brush black = new SolidBrush(Color.Black);
            Pen pen = new Pen(black);

            // Check if the current project is empty
            if (projectRevisionArray != null)
            {
                // Set trackbar properties
                trackBar.TickFrequency = 0;
                trackBar.Maximum = projectRevisionArray.Length-1;

                // Draw animation
                if (trackBar.Value < projectRevisionArray.Length)
                {
                    // Displays the revision as specified by the trackbar position
                    C_Frame animationFrame = new C_Frame(projectRevisionArray[trackBar.Value], this.Width, this.Height - 150, new Point(0, 0));
                    animationFrame.Draw(sender, e);
                }
                else
                {
                    // Displays the last revision in project
                    C_Frame animationFrame = new C_Frame(projectRevisionArray[projectRevisionArray.Length - 1], this.Width, this.Height - 150, new Point(0, 0));
                    animationFrame.Draw(sender, e);
                }
            }
        }

        /// <summary>
        /// Is called when "Pause" is clicked on in the Navigation Menu
        /// or when the Pause button is clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PauseClick(object sender, EventArgs e)
        {
            PauseClick();
        }

        /// <summary>
        /// Stops the animation if it is playing.
        /// Does nothing if the animation is stopped.
        /// </summary>
        private void PauseClick()
        {
            isPlaying = false;
        }

        /// <summary>
        /// Handles the playing of the current animation.
        /// Plays when isPlaying is true.
        /// Does not play is isPlaying is false.
        /// </summary>
        private void Play()
        {
            // Check to see if we should be playing
            while (isPlaying)
            {
                // Scrolls through the trackbar to show each frame consecutively
                this.BeginInvoke(new scrollDel(ScrollTrackBarNext));
                Thread.Sleep(200);
                if (trackVal == trackBar.Maximum)
                    isPlaying = false;
            }
        }

        /// <summary>
        /// Is called when the user changes the size of the form.
        /// Redraws the screen.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ResizeForm(object sender, EventArgs e) 
        { 
            this.Invalidate();
            AnimationBox.Invalidate(); 
        }

        /// <summary>
        /// Is called when the trackbar position is changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScrollTrackBar(object sender, EventArgs e)
        {
            ScrollTrackBar();
        }

        /// <summary>
        /// Changes the position of the trackbar and updates the 
        /// revision label.
        /// </summary>
        private void ScrollTrackBar()
        {
            // Display the trackbar value in the text box.
            this.revisionPositionLabel.Text = "" + (trackBar.Value+1) + "//" + (trackBar.Maximum+1);

            // Keep track of the trackbar value
            trackVal = trackBar.Value;

            // Repaint
            this.Invalidate();
            AnimationBox.Invalidate();
        }

        /// <summary>
        /// Is called when "Next" is clicked on under the Navigation Menu
        /// or when the Next button is clicked.
        /// Pauses the animation if playing and displays the next revision.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScrollTrackBarNext(object sender, EventArgs e)
        {
            // Pause
            isPlaying = false;

            // Display next revision
            ScrollTrackBarNext();
        }

        /// <summary>
        /// Moves the trackbar to the next position which effectly
        /// displays the next revision.
        /// </summary>

        private void ScrollTrackBarNext()
        {
            // Add one to the current position unless we are at the last position
            if (trackBar.Value < trackBar.Maximum)
                trackBar.Value++;
            // We are at the last position so reset the position to zero
            else
                trackBar.Value = 0;
            
            // Update trackbar location
            ScrollTrackBar();
        }

        /// <summary>
        /// Is called when "Previous" is clicked on under the Navigation Menu
        /// or when the Previous button is clicked.
        /// Pauses the animation and displays the previous revision.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ScrollTrackBarPrevious(object sender, EventArgs e)
        {
            isPlaying = false;
            ScrollTrackBarPrevious();
        }
        
        /// <summary>
        /// Moves the trackbar to the previous position which effectly
        /// displays the previous revision.
        /// </summary>
        private void ScrollTrackBarPrevious()
        {
            // Decreases the trackbar position by one unless we are at position zero
            if (trackBar.Value > trackBar.Minimum)
                trackBar.Value--;
            // Sets the trackbar position to the last revision if wer are at position zero
            else
                trackBar.Value = trackBar.Maximum;

            // Updates trackbar position
            ScrollTrackBar();
        }

        /// <summary>
        /// Displays an error message box.
        /// </summary>
        /// <param name="reason"></param>
        public void ShowErrorMessage(String reason)
        {
            // Display an error as described by reason
            MessageBox.Show(reason, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// Converts the project data structure into a tree of shapes
        /// that can be used to directly draw the animation.
        /// </summary>
        public void TranslateRevision()
        {
            try
            {
                // This adjusts from a 1 based to zero based system
                projectRevisionArray = new C_Shape[projectValidLength-1][];

                System.Diagnostics.Debug.WriteLine("Shape proj size: " + projectRevisionArray.Length);
                
                // Loop through revisions
                for (int i = 0; i < projectRevisionArray.Length; i++)
                {
                    projectRevisionArray[i] = ConvertDataToTree(projectDataStructure[i+1]);
                    System.Diagnostics.Debug.WriteLine("Translated " + (i+1) + ":");

                    System.Diagnostics.Debug.WriteLine("    Proj[ " + (i+1) + "] size: " + projectRevisionArray[i].Length + " down from " + projectDataStructure[i+1].Length);
                }   
            }
            catch
            {
                System.Diagnostics.Debug.WriteLine("Translate Revision has failed");
            }
        }
    }
}